package com.ruoyi.business.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.ruoyi.bizsys.domain.*;
import com.ruoyi.bizsys.mapper.ExtPaystackCustVaResultMapper;
import com.ruoyi.bizsys.service.*;
import com.ruoyi.bizsys.utils.BizConstants;
import com.ruoyi.business.component.MqProduce;
import com.ruoyi.business.component.RepaymentMqSendService;
import com.ruoyi.business.component.mqconsumer.LoanResultConsume;
import com.ruoyi.business.domain.WalletOrderReq;
import com.ruoyi.business.service.*;
import com.ruoyi.business.util.MonnifyUtils;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.constant.WalletConstants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.RspEnmu;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.utils.Func;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.extdata.common.config.MonnifyConfig;
import com.ruoyi.extdata.service.IExternalApiService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.ParseException;
import java.util.Date;

/**
 * @Author: Jamnsin
 * @Date: 2021/6/12 1:02 上午
 */
@Slf4j
@Service
public class CallbackServiceImpl extends BaseService implements ICallbackService {

    @Autowired
    ICustBindCardLogService bindCardLogService;

    @Autowired
    IRepaymentOrderService repaymentOrderService;

    @Autowired
    IBLoanInfoService bLoanInfoService;

    @Autowired
    IBankCardService bankCardService;

    @Autowired
    IRepaymentService repaymentService;

    @Autowired
    ILoanOrderService loanOrderService;

    @Autowired
    IExternalApiService externalApiService;

    @Autowired
    MonnifyConfig monnifyConfig;

    @Autowired
    IRepaymentOrderService iRepaymentOrderService;

    @Autowired
    IBRepaymentService ibRepaymentService;

    @Autowired
    IExtMonnifyOrderService iExtMonnifyOrderService;

    @Autowired
    RedisCache redisCache;

    @Autowired
    ILoanIouService loanIouService;

    @Autowired
    IMonnifyRepaymentService monnifyRepaymentService;

    @Autowired
    private MqProduce mqProduce;

    @Autowired
    IWalletService walletService;

    @Autowired
    RepaymentMqSendService repaymentMqService;

    @Autowired
    ICustVaService delCustVaService;
    @Autowired
    ExtPaystackCustVaResultMapper extPaystackCustVaResultMapper;

//    @PostConstruct
//    public void test(){
//        String json = "{\"event\":\"customeridentification.success\",\"data\":{\"customer_id\":87414764,\"customer_code\":\"CUS_w7bxqu3jhbvb8yv\"}}";
//        dealEvent(JSONObject.parseObject(json));
//    }


    @Override
    // @Transactional 事物中不能发送mq
    public void dealEvent(JSONObject res) throws ParseException {
        // 回调事件：{"event":"charge.success","data":{"id":1155459776,"domain":"live","status":"success","reference":"2021060118562868413024256","amount":5000,"message":"","gateway_response":"Approved","paid_at":"2021-06-01T18:57:39.000Z","created_at":"2021-06-01T18:56:28.000Z","channel":"card","currency":"NGN","ip_address":"197.210.71.245","metadata":"","log":{"start_time":1622573790,"time_spent":23,"attempts":1,"authentication":"3DS","errors":0,"success":false,"mobile":true,"input":[],"history":[{"type":"input","message":"Filled this field: card number","time":5},{"type":"input","message":"Filled this field: card expiry","time":9},{"type":"input","message":"Filled this field: card cvv","time":11},{"type":"action","message":"Attempted to pay with card","time":11},{"type":"auth","message":"Authentication Required: 3DS","time":20},{"type":"action","message":"Third-party authentication window opened","time":23}]},"fees":75,"fees_split":null,"authorization":{"authorization_code":"AUTH_0tyjcwsh7q","bin":"539941","last4":"4141","exp_month":"09","exp_year":"2022","channel":"card","card_type":"mastercard DEBIT","bank":"Zenith Bank","country_code":"NG","brand":"mastercard","reusable":true,"signature":"SIG_ddyamioym1m70hh0fUMD","account_name":"FAROUK   GARUBA"},"customer":{"id":46343082,"first_name":null,"last_name":null,"email":"88f743d29a@lcserver.com","customer_code":"CUS_z6ye554bo116llz","phone":null,"metadata":null,"risk_action":"default","international_format_phone":null},"plan":{},"subaccount":{},"split":{},"order_id":null,"paidAt":"2021-06-01T18:57:39.000Z","requested_amount":5000,"pos_transaction_data":null,"source":{"type":"api","source":"merchant_api","identifier":null}},"order":null,"business_name":"LinkCredit"}
        String event = res.get("event") == null ? "" : res.getString("event");
        if (StringUtils.isBlank(event)) {
            return;
        }

        JSONObject data = res.getJSONObject("data");
        switch (event) {
            case "charge.success":
                // 代扣回调
                dealPaystackCharge(data);
                break;
            case "transfer.failed":
            case "transfer.success":
                // 放款/提现回调
                dealPaystackTransfer(event, data);
                break;
            case "transfer.reversed":
//                dealLoan(data);
                break;
            case "customeridentification.success":
                dealCustomeridentification(true, data);
                break;
            case "customeridentification.failed":
                dealCustomeridentification(false, data);
                break;
            default:

        }
    }

    /**
     * 处理
     * Validate Customer结果是通过webhook返回事件：
     * 验证成功事件：event=customeridentification.success；
     * 验证失败事件：event=customeridentification.failed；
     *
     * @param isSuccess
     */
    private void dealCustomeridentification(boolean isSuccess, JSONObject data) {
        String customerId = data.getString("customer_id");
        ExtPaystackCustVaResult extPaystackCustVaResult = extPaystackCustVaResultMapper.getDetailByCustomerId(customerId);
        if (isSuccess) {
            log.info("customer_id:{}customeridentification.success", customerId);
            extPaystackCustVaResultMapper.updateStatusByCustomerId(customerId, ExtPaystackCustVaResult.STATUS_SUCCESS);
            delCustVaService.createCustVaForPaystack(extPaystackCustVaResult);
        } else {
            log.info("customer_id:{}customeridentification.failed", customerId);
            extPaystackCustVaResultMapper.updateStatusByCustomerId(customerId, ExtPaystackCustVaResult.STATUS_FAILD);
        }
    }

    @Override
    @Transactional
    public void webHookMonnify(JSONObject parseObject, String custNo) {
        //checkWebHookStatus这里存 insertExtMonnifyOrder
        ExtMonnifyOrder extMonnifyOrder = monnifyRepaymentService.checkWebHookStatus(parseObject, custNo);
        if (extMonnifyOrder == null) {
            return;
        }
        //判断时transferTous还是card
        String type = parseObject.getJSONObject("product").getString("type");

        if ("RESERVED_ACCOUNT".equals(type)) {
            JSONObject jsonObjectForMq = createJsonData(extMonnifyOrder, custNo);
            repaymentMqService.syncSendMqRepayMentMonnify(jsonObjectForMq, custNo);

//            monnifyRepaymentService.repaymentLock(extMonnifyOrder);
//            //删除redis
//            redisCache.deleteObject(BizConstants.TRANSFER_TO_US_THREAD+custNo);
        } else {
            //ussd
            //transferToUs
            //3.查看该订单是否已经结算完
            RepaymentOrder repaymentOrder = getRepaymentOrder(parseObject);
            //更新第三方订单表
            extMonnifyOrder = new ExtMonnifyOrder();
            extMonnifyOrder.setTransactionReference(parseObject.getString("transactionReference"));
            extMonnifyOrder.setState(UserConstants.BUSINESS_NORMAL);
            if ("WEB_SDK".equals(type)) {
                //card
                extMonnifyOrder.setType(BizConstants.MONNFIY_ORDER_TYPE_CARD);
            } else {
                extMonnifyOrder.setType(BizConstants.MONNFIY_ORDER_TYPE_USSD);
            }
            extMonnifyOrder = iExtMonnifyOrderService.selectExtMonnifyOrderList(extMonnifyOrder).get(0);

            extMonnifyOrder = MonnifyUtils.setExtMonnifyOrderWebHook(parseObject, custNo);


            iExtMonnifyOrderService.updateExtMonnifyOrder(extMonnifyOrder);

            ibRepaymentService.transactionStatusSuccess(repaymentOrder, parseObject.getBigDecimal("amountPaid"), new Date(), "TTS-Webhook");
            // 删除redis
            redisCache.deleteObject(BizConstants.TRANSACTION_THREAD + parseObject.getString("paymentReference"));
        }

    }

    private JSONObject createJsonData(ExtMonnifyOrder extMonnifyOrder, String custNo) {
        JSONObject res = new JSONObject();
        res.put("extMonnifyOrder", extMonnifyOrder);
        res.put("custNo", custNo);
        return res;
    }


    private RepaymentOrder getRepaymentOrder(JSONObject parseObject) {
        RepaymentOrder repaymentOrder = new RepaymentOrder();
        repaymentOrder.setState(UserConstants.BUSINESS_NORMAL);
        repaymentOrder.setRepaymentNo(parseObject.getString("paymentReference"));
        repaymentOrder.setRepayStatus(BizConstants.REPAYMENT_ORDER_STATUS_WAIT);
        repaymentOrder = iRepaymentOrderService.getDetail(repaymentOrder);
        if (repaymentOrder == null) {
            throw new BusinessException(parseObject.getString("paymentReference"), RspEnmu.MONNIFY_TRANSACTION_WEBHOOK_STATUS_ERROR);
        }
        return repaymentOrder;
    }

    private void dealPaystackTransfer(String eventType, JSONObject data) {
        log.info("处理 PaystackTransfer webhook >>> eventType = {}", eventType);

        String reference = data.getString("reference");
        externalApiService.dealTransferData(eventType, "webhook", data);

        // 放款结果
        String actionType = getActionType(reference);
        log.debug("actionType = {}", actionType);

        if (StringUtils.equals(actionType, BizConstants.LOAN_ACTION_TYPE_FLAG)) {
            if (dealLoanResult(eventType, reference)) {
                return;
            }
        }

        // 提现结果
        if (StringUtils.equalsAny(actionType, BizConstants.WITHDRAW_ACTION_TYPE_FLAG, BizConstants.REFUND_ACTION_TYPE_FLAG)) {
            // String serialNo = reference.replace(BizConstants.SERIALNO_WITHDRAW_FLAG, "").replace(BizConstants.SERIALNO_REFUND_FLAG, "");
            dealWalletWithdrawResult(eventType, actionType, reference, getValue(data, "gateway_response"));
        }
    }

    private void dealWalletWithdrawResult(String eventType, String actionType, String serialNo, String message) {
        log.info("处理提现结果，eventType = {}，actionType = {}，serialNo = {}", eventType, actionType, serialNo);

        String orderType = getOrderType(actionType);
        log.debug("订单类型： {}", orderType);

        WalletOrderReq walletOrderReq = WalletOrderReq.builder().orderSerialNo(serialNo).approvalStatus(getOrderStatus(eventType)).orderType(WalletConstants.ORDER_TYPE_WITHDRAW).message(message).build();
        walletService.updateWalletOrder(walletOrderReq);
    }

    private String getValue(JSONObject json, String fieldName) {
        return json.get(fieldName) == null ? "" : json.getString(fieldName);
    }

    private String getOrderType(String actionType) {
        if (StringUtils.equals(actionType, BizConstants.WITHDRAW_ACTION_TYPE_FLAG)) {
            return WalletConstants.ORDER_TYPE_WITHDRAW;
        }

        if (StringUtils.equals(actionType, BizConstants.REFUND_ACTION_TYPE_FLAG)) {
            return WalletConstants.ORDER_TYPE_REFUND;
        }

        throw new BusinessException(RspEnmu.WALLET_WITHDRAW_TYPE_CANNOT_SUPPORT);
    }

    private String getOrderStatus(String eventType) {
        if (StringUtils.equals(eventType, "transfer.success")) {
            return WalletConstants.WALLET_ORDER_STATUS_SUCCESS;
        } else if (StringUtils.equals(eventType, "transfer.failed")) {
            return WalletConstants.WALLET_ORDER_STATUS_FAILED;
        }
        throw new BusinessException(RspEnmu.WEBHOOK_EVENT_TYPE_UNSUPPORTED);
    }

    private boolean dealLoanResult(String eventType, String reference) {
        log.info("处理放款结果，eventType = {}，reference = {}", eventType, reference);

        LoanOrder loanOrder = loanOrderService.getOneByPayTransSerialNo(reference);
        if (Func.isEmpty(loanOrder)) {
            log.info("未查找到此支付流水号记录");
            return true;
        }

        if (loanOrder.getLoanStatus() == 4) {
            log.info("提现订单状态已变更，无需处理");
            return true;
        }

        //判断
        if (StringUtils.equals(eventType, "transfer.success")) {
            mqProduce.sendLoanResultOrderly(loanOrder.getLoanSerialNo(), LoanResultConsume.SUCCESS, loanOrder.getCustNo());
        } else if (StringUtils.equals(eventType, "transfer.falied")) {
            mqProduce.sendLoanResultOrderly(loanOrder.getLoanSerialNo(), LoanResultConsume.FAILED, loanOrder.getCustNo());
        }
        return false;
    }

    private String getActionType(String reference) {
        if (!reference.contains(BizConstants.SERIALNO_SEPARATOR_FLAG)) {
            return BizConstants.LOAN_ACTION_TYPE_FLAG;
        } else {
            return reference.split(BizConstants.SERIALNO_SEPARATOR_FLAG)[1];
        }
    }

    private void dealPaystackCharge(JSONObject data) throws ParseException {
        String serialNo = data.getString("reference");
        if (serialNo.indexOf(BizConstants.PAY_TRANS_FLAG_BIND_CARD) != -1) {
            // 办卡操作
            bindCardWebhook(serialNo, data);
            return;
        }

        String transferChannel = data.getString("channel");
        log.info("paystack charge event channel:: {}", transferChannel);
        // 记录webhook数据
        externalApiService.dealTransferData("charge.success", "webhook", null, data);
        if (BizConstants.PAYSTACK_TRANSFER_CHANNEL_CARD.equals(transferChannel)) {
            // 非虚拟账号还款
            checkReference(serialNo, data);
            return;
        }
        if (BizConstants.PAYSTACK_TRANSFER_CHANNEL_VA.equals(transferChannel)) {
            log.info("处理虚拟账号还款::{},{}", serialNo, data.toJSONString());
            String custNo = getCustNoFromPaystackReservedAccounts(data.getJSONObject("customer"));
            repaymentMqService.webhookVaRepayment(serialNo, custNo);
            return;
        }
    }

    private String getCustNoFromPaystackReservedAccounts(JSONObject customerObj) {
        return extPaystackCustVaResultMapper.getDetailByCustomerId(customerObj.getString("id")).getCustNo();
    }

    private void bindCardWebhook(String serialNo, JSONObject data) {
        CustBindCardLog bindCardLog = bindCardLogService.getDetailBySerialNo(serialNo);
        //绑卡回调
        if (null != bindCardLog) {
            String eventType;
            eventType = "bind.success";
            externalApiService.dealTransferData(eventType, "webhook", bindCardLog.getCustNo(), data);
            if (!StringUtils.equals(bindCardLog.getTransStatus(), BizConstants.BIND_CARD_TRANS_SUCCESS)) {
                bankCardService.dealBindSuccess(bindCardLog, data);
            }
        }
    }

    /**
     * @param reference 后缀| 进行分割 PAY_TRANS_FLAG_?
     *                  |DF  延期
     *                  |DFWALLET 延期含钱包
     *                  |PAYALLWALLET 全额含有钱包
     */
    private void checkReference(String reference, JSONObject data) {
        log.info("reference:{},data:{}", reference, data.toJSONString());
        RepaymentOrder repaymentOrder = repaymentOrderService.getDetailByPayTransSerialNoStatusSucc(reference);
//        Instant timestamp = Instant.parse(data.getString("paid_at"));
//        repaymentOrder.setPayTime(Date.from(timestamp));
        // 需求问题，不处理，需要和产品沟通，不需要处理。
        //repaymentOrderService.updateById(repaymentOrder);
        if (BizConstants.REPAYMENT_ORDER_STATUS_WAIT == repaymentOrder.getRepayStatus()) {
            log.info("webhook回调，查询repaymentOrder，已经成功了不需要处理reference：{},repaymentOrderNo:{}", reference, repaymentOrder.getRepaymentNo());
            return;
        }
        if (BizConstants.REPAYMENT_ORDER_STATUS_FAIL == repaymentOrder.getRepayStatus()) {
            log.info("webhook回调，查询repaymentOrder，是失败，需要改成5进行mq消费，reference：{},repaymentOrderNo:{}", reference, repaymentOrder.getRepaymentNo());
            repaymentOrder.setRepayStatus(BizConstants.REPAYMENT_ORDER_STATUS_DOING);
            repaymentOrder.setRemark(repaymentOrder.getRemark() + " :: webhook回调，查询repaymentOrder失败改成5进行mq消费");
            repaymentOrderService.updateRepaymentOrder(repaymentOrder);
        }
        // 判断|DF的标示进行发送到不同的mq进行处理
        // 正常还款无钱包-无延期购买
        if (reference.indexOf(BizConstants.SERIALNO_SEPARATOR_FLAG) == -1) {
            repaymentMqService.webhookRepayment(repaymentOrder, data);
            return;
        }

        // 余额代扣
        if (reference.indexOf(BizConstants.PAY_TRANS_FLAG_CARD_WITHHOLD) != -1) {
            repaymentMqService.cardBatchDebitRepayment(repaymentOrder, data);
            return;
        }


        //有钱包-正常全额还款
        if (reference.indexOf(BizConstants.PAY_TRANS_FLAG_PAY_ALL_WALLET) != -1) {
            CreditAccount creditAccount = creditAccountService.getNormalAcountOnLoan(repaymentOrder.getCustNo());
            if (null != creditAccount) {
                repaymentMqService.selfWalletForBfenRepaymentMq(repaymentOrder, creditAccount.getId());
            }
            return;
        }

        //无钱包-有延期购买
        if (reference.indexOf(BizConstants.PAY_TRANS_FLAG_DF) != -1) {
            CreditAccount creditAccount = creditAccountService.getNormalAcountOnLoan(repaymentOrder.getCustNo());
            if (null != creditAccount) {
                repaymentMqService.selfdeferRepaymentMq(repaymentOrder, creditAccount);
            }
            return;
        }

        // 场景 有钱包100-延期购买卡支付2900 共3000
        if (reference.indexOf(BizConstants.PAY_TRANS_FLAG_DF_WALLET) != -1) {
            CreditAccount creditAccount = creditAccountService.getNormalAcountOnLoan(repaymentOrder.getCustNo());
            if (null != creditAccount) {
                repaymentMqService.selfdeferWalletForBfenRepaymentMq(repaymentOrder, creditAccount);
            }
            return;
        }
    }
}
